package tcp

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net"
	"strconv"
	"sync"
	"time"
)

// Message 创建需要传递数据
// 自定义消息体结构
// `json:"id,omitempty"` 进行json传输时 会将ID 转换成小写id，omitempty：表示这个字段为零值或者是null值会被忽略掉
type Message struct {
	ID      uint      `json:"id,omitempty"`
	Code    string    `json:"code,omitempty"`
	Content string    `json:"content,omitempty"`
	Time    time.Time `json:"time,omitempty"`
}

var tcp = "tcp"

// TcpServiceSort 服务端短链接
func TcpServiceSort() {
	// 基于某个地址建立监听
	// 服务端地址
	listener, err := net.Listen(tcp, ":5678")
	if err != nil {
		log.Fatalln(err)
	}

	// 关闭监听
	defer listener.Close()
	log.Printf("%s server is listening on %s\n", tcp, listener.Addr())

	// 接受连接请求
	for {
		// 阻塞请求
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err)
		}

		// 处理连接，读写
		go HandleConnSort(conn)
	}
}

func HandleConnSort(conn net.Conn) {
	// 远程连接地址
	log.Printf("Accept connection from %s\n", conn.RemoteAddr())
	defer conn.Close()

	wg := sync.WaitGroup{}
	wg.Add(1)

	go SerWriteSort(conn, &wg)
	wg.Wait()
}

func SerWriteSort(conn net.Conn, wg *sync.WaitGroup) {
	defer wg.Done()

	message := Message{
		ID:      1,
		Code:    "SERVER-STANDARD",
		Content: "message from sever",
	}

	// 创建编码器 json encode成功后，会写入到conn
	encoder := json.NewEncoder(conn)
	if err := encoder.Encode(message); err != nil {
		log.Println(err)
		return
	}
	log.Println("message sent")
	log.Println("link wat close")
	return
}

// TcpClientSort 客户端短链接
func TcpClientSort() {
	// tcp服务端地址
	serverAddress := "127.0.0.1:5678"

	// A. 建立连接
	conn, err := net.DialTimeout(tcp, serverAddress, time.Second)
	//conn, err := net.Dial(tcp, serverAddress)
	if err != nil {
		log.Println(err)
		return
	}

	// 保证关闭
	defer conn.Close()

	log.Printf("connection is establish, client addr is %s\n", conn.LocalAddr())
	wg := sync.WaitGroup{}

	wg.Add(1)
	go ClientReadSort(conn, &wg)
	wg.Wait()
}

func ClientReadSort(conn net.Conn, wg *sync.WaitGroup) {
	defer wg.Done()
	message := Message{}

	for {
		// JSON 解码 用解码器进行解码。从conn读取内容，进行解码赋值到message变量
		decoder := json.NewDecoder(conn)
		// 错误表示为 io.EOF 表示连接被关闭
		if err := decoder.Decode(&message); err != nil && errors.Is(err, io.EOF) {
			log.Println(err)
			log.Println("link was closed")
			break
		}

		log.Println(message)
	}
}

// TcpServiceHB 长连接 心跳检测
func TcpServiceHB() {
	// 基于某个地址建立监听
	// 服务端地址
	listener, err := net.Listen(tcp, ":5678")
	if err != nil {
		log.Fatalln(err)
	}

	// 关闭监听
	defer listener.Close()
	log.Printf("%s server is listening on %s\n", tcp, listener.Addr())

	// 接受连接请求
	for {
		// 阻塞请求
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err)
		}

		// 处理连接，读写
		go HandleConnHB(conn)
	}
}

func HandleConnHB(conn net.Conn) {
	// 远程连接地址
	log.Printf("Accept connection from %s\n", conn.RemoteAddr())
	defer conn.Close()

	// 独立的gorouing 在建立连接之后，周期发送ping
	wg := sync.WaitGroup{}
	wg.Add(1)

	go SerPing(conn, &wg)
	wg.Wait()
}

func SerPing(conn net.Conn, wg *sync.WaitGroup) {
	defer wg.Done()

	//周期性发送 利用time.TicKer
	ticKer := time.NewTicker(2 * time.Second)
	for t := range ticKer.C {
		message := Message{
			ID:   uint(rand.Int()),
			Code: "PING-SERVER",
			Time: t,
		}
		// 创建编码器 json encode成功后，会写入到conn
		encoder := json.NewEncoder(conn)
		if err := encoder.Encode(message); err != nil {
			log.Println(err)
		}
		log.Println("ping send to ", conn.RemoteAddr())
	}

}

func TcpClientHB() {
	// tcp服务端地址
	serverAddress := "127.0.0.1:5678"

	// A. 建立连接
	conn, err := net.DialTimeout(tcp, serverAddress, time.Second)
	//conn, err := net.Dial(tcp, serverAddress)
	if err != nil {
		log.Println(err)
		return
	}

	// 保证关闭
	defer conn.Close()

	log.Printf("connection is establish, client addr is %s\n", conn.LocalAddr())
	wg := sync.WaitGroup{}

	wg.Add(1)
	go ClientReadPing(conn, &wg)
	wg.Wait()
}

func ClientReadPing(conn net.Conn, wg *sync.WaitGroup) {
	defer wg.Done()
	message := Message{}

	for {
		// JSON 解码 用解码器进行解码。从conn读取内容，进行解码赋值到message变量
		decoder := json.NewDecoder(conn)
		// 错误表示为 io.EOF 表示连接被关闭
		if err := decoder.Decode(&message); err != nil && errors.Is(err, io.EOF) {
			log.Println(err)
			log.Println("link was closed")
			break
		}

		log.Println(message)
		//判断是否是 ping 类型
		if message.Code == "PING-SERVER" {
			log.Println("send pong to server")
			ClientWritePong(conn, message)
		}
	}
}

func ClientWritePong(conn net.Conn, pongMessage Message) {

	message := Message{
		ID:      uint(rand.Int()),
		Code:    "PONG-CLIENT",
		Content: fmt.Sprintf("pintID(%d)", pongMessage.ID),
		Time:    time.Now(),
	}

	// 创建编码器 json encode成功后，会写入到conn
	encoder := json.NewEncoder(conn)
	if err := encoder.Encode(message); err != nil {
		log.Println(err)
	}
	log.Println("pong was send to", conn.RemoteAddr())
}

// TcpServicePool 连接池
func TcpServicePool() {
	// 基于某个地址建立监听
	// 服务端地址
	listener, err := net.Listen(tcp, ":5678")
	if err != nil {
		log.Fatalln(err)
	}

	// 关闭监听
	defer listener.Close()
	log.Printf("%s server is listening on %s\n", tcp, listener.Addr())

	// 接受连接请求
	for {
		// 阻塞请求
		conn, err := listener.Accept()
		if err != nil {
			log.Println(err)
		}

		// 处理连接，读写
		go HandleConnPool(conn)
	}
}

func HandleConnPool(conn net.Conn) {
	// 远程连接地址
	log.Printf("Accept connection from %s\n", conn.RemoteAddr())

	defer func() {
		conn.Close()
		log.Println("connection is closed")
	}()
}

func TcpClientPool() {
	// tcp服务端地址
	serverAddress := "127.0.0.1:5678"

	// A. 建立连接池
	pool, err := NewTcpPool(serverAddress, PoolConfig{
		Factory:     &TcpConnFactory{},
		InitConnNum: 2,
		MaxConnNum:  6,
	})
	if err != nil {
		log.Fatalln(err)
	}

	log.Println(pool, pool.Len())
	wg := sync.WaitGroup{}
	clientNum := 58
	wg.Add(clientNum)

	// 复用连接池中的连接
	for i := 0; i < clientNum; i++ {
		go func(wg *sync.WaitGroup) {
			defer wg.Done()
			// 获取连接
			conn, err := pool.Get()
			if err != nil {
				log.Println("pool put error", err)
				return
			}

			// 回收连接
			if err := pool.Put(conn); err != nil {
				log.Println("pool put error", err)
				return

			}

		}(&wg)
	}
	wg.Wait()

	err = pool.Release()
	if err != nil {
		log.Printf("release pool errpt = %s\n", err)
	}
	// 释放连接池
	log.Printf("release pool = %+v\n, idleList = %v\n, len = %d", pool, pool.idleList, pool.Len())
}

// TcpServerSpecial tcp 连接特定方法
func TcpServerSpecial() {
	// 建立连接，获取本地连接地址（监听地址）
	laddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:5678")
	if err != nil {
		log.Fatalln(err)
	}
	tcpListener, err := net.ListenTCP("tcp", laddr)
	if err != nil {
		log.Fatalln(err)
	}

	defer func(tcpListener *net.TCPListener) {
		err := tcpListener.Close()
		if err != nil {
			log.Fatalln(err)
		}
	}(tcpListener)
	log.Printf("%s server is listening on %s\n", tcp, tcpListener.Addr())

	// 接收连接
	for {
		tcpConn, err := tcpListener.AcceptTCP()
		if err != nil {
			log.Println(err)
			continue
		}

		// 处理每个连接
		go handleConnSpecial(tcpConn)
	}

}

func handleConnSpecial(conn *net.TCPConn) {
	log.Printf("Accept connection from %s\n", conn.RemoteAddr())
	// 写数据
	number := 10
	for i := 0; i < number; i++ {
		data := "tcp message" + strconv.Itoa(i)
		in, err := conn.Write([]byte(data))
		if err != nil {
			log.Println(err)
			return
		}
		log.Println("send len:", in)
	}
}

func TcpClientSpecial() {
	// 建立连接，raddr remote addr 服务端的地址
	tcpAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:5678")
	if err != nil {
		log.Fatalln(err)
	}
	// laddr local addr 客户端的地址，可以用于设置客户端的端口
	conn, err := net.DialTCP("tcp", nil, tcpAddr)
	if err != nil {
		log.Fatalln(err)
	}
	defer conn.Close()

	// 读数据
	buf := make([]byte, 1024)
	for {
		n, err := conn.Read(buf)
		if err != nil {
			log.Fatalln(err)
			return
		}
		log.Println("receive len:", n)
		log.Println("receive date", string(buf[0:n]))
		if n == 0 {
			return
		}
	}
}
